package com.xpxrule.util;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xpxrule.constant.Operator;
import com.xpxrule.constant.ValueType;
import com.xpxrule.dataobject.base.Range;
import com.xpxrule.dataobject.bo.RuleConditionItemBo;
import com.xpxrule.dataobject.bo.RuleResultItemBo;
import com.xpxrule.dataobject.dao.ConstantItem;
import com.xpxrule.dataobject.dao.Rule;
import com.xpxrule.dataobject.vo.RuleDisplayVo;
import com.xpxrule.service.ConstantItemService;
import com.xpxrule.strategy.FieldTypeStrategyContext;
import com.xpxrule.strategy.field.FieldTypeStrategy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
public class FieldDisplayUtil {
    public static final String CONDITION_DISPLAY_TEXT_FORMAT = "%s 【%s】 %s";
    public static final String RESULT_DISPLAY_TEXT_FORMAT = "%s ：%s";

    @Autowired
    private ConstantItemService constantItemService;

    public RuleDisplayVo convertRuleToRuleDisplayVo(Rule rule) {
        RuleDisplayVo vo = new RuleDisplayVo();
        vo.setId(String.valueOf(rule.getId()));
        vo.setRuleName(rule.getRuleName());
        vo.setScenariosKey(rule.getScenariosKey());
        List<String> conditionDisplayTextList = convertConditionStringToDisplayText(rule.getConditionDetail());
        vo.setConditionDetail(conditionDisplayTextList);
        List<String> resultDisplayTextList = convertResultStringToDisplayText(rule.getResultDetail());
        vo.setResultDetail(resultDisplayTextList);
        vo.setResultAction(rule.getResultAction());
        vo.setDescription(rule.getDescription());
        vo.setStartEffectTime(rule.getStartEffectTime());
        vo.setEndEffectTime(rule.getEndEffectTime());
        vo.setIsEnable(rule.getIsEnable());
        return vo;
    }

    public String ruleConditionItemBoConvertDisplayText(RuleConditionItemBo conditionItemBo) {
        String field = conditionItemBo.getFieldName();
        Operator operator = conditionItemBo.getOperator();
        String targetValueDisplayText = getConditionItemDisplayTargetValue(conditionItemBo);
        return String.format(CONDITION_DISPLAY_TEXT_FORMAT, field, operator.getDisplayText(), targetValueDisplayText);
    }

    private String getConditionItemDisplayTargetValue(RuleConditionItemBo conditionItemBo) {
        String fieldValueType = conditionItemBo.getFieldValueType();
        String targetValue = "";
        switch (fieldValueType) {
            case "basic":
                // 基础类型
                targetValue = getConditionItemBasicTypeDisplayTargetValue(conditionItemBo);
                break;
            case "enumConstant":
                // 枚举类型
                targetValue = getConditionEnumConstantDisplayTargetValue(conditionItemBo);
                break;
        }
        return targetValue;
    }

    private String getConditionEnumConstantDisplayTargetValue(RuleConditionItemBo conditionItemBo) {
        /**
         * 获取枚举常量下所有枚举明细项
         */
        List<ConstantItem> constantItemList = constantItemService.getConstantItemByEnumConstantKey(conditionItemBo.getType());
        // 枚举常量转为map
        Map<String, ConstantItem> constantItemMap = new HashMap<>();
        for (ConstantItem constantItem : constantItemList) {
            constantItemMap.put(constantItem.getItemKey(), constantItem);
        }
        ValueType valueType = conditionItemBo.getTargetValue().getValueType();
        FieldTypeStrategy fieldTypeStrategy = FieldTypeStrategyContext.getFieldTypeStrategy(conditionItemBo.getFieldBasicType());
        String displayText = "";
        switch (valueType) {
            case SINGLE:
                Object single = conditionItemBo.getTargetValue().getSingle();
                displayText = fieldTypeStrategy.getSingleValueDisplayText(constantItemMap.get(single.toString()).getItemName());
                break;
            case RANGE:
                Range range = conditionItemBo.getTargetValue().getRange();
                String beginItem = constantItemMap.get(range.getBegin().toString()).getItemName();
                String endItem = constantItemMap.get(range.getEnd().toString()).getItemName();
                displayText = fieldTypeStrategy.getRangeValueDisplayText(new Range<>(beginItem, endItem));
                break;
            case COLLECTION:
                List list = conditionItemBo.getTargetValue().getList();
                List<String> itemList = new ArrayList<>();
                for (Object item : list) {
                    itemList.add(constantItemMap.get(item.toString()).getItemName());
                }
                displayText = fieldTypeStrategy.getCollectionValueDisplayText(itemList);
                break;
        }
        return displayText;
    }

    private String getConditionItemBasicTypeDisplayTargetValue(RuleConditionItemBo conditionItemBo) {
        ValueType valueType = conditionItemBo.getTargetValue().getValueType();
        FieldTypeStrategy fieldTypeStrategy = FieldTypeStrategyContext.getFieldTypeStrategy(conditionItemBo.getFieldBasicType());
        String displayText = "";
        switch (valueType) {
            case SINGLE:
                displayText = fieldTypeStrategy.getSingleValueDisplayText(conditionItemBo.getTargetValue().getSingle());
                break;
            case RANGE:
                displayText = fieldTypeStrategy.getRangeValueDisplayText(conditionItemBo.getTargetValue().getRange());
                break;
            case COLLECTION:
                displayText = fieldTypeStrategy.getCollectionValueDisplayText(conditionItemBo.getTargetValue().getList());
                break;
        }
        return displayText;
    }

    public List<String> convertConditionStringToDisplayText(String conditionDetail) {
        ObjectMapper objectMapper = new ObjectMapper();
        List<String> result = new ArrayList<>();
        try {
            List<RuleConditionItemBo> conditionItemBoList = objectMapper.readValue(conditionDetail, new TypeReference<List<RuleConditionItemBo>>() {
            });
            for (RuleConditionItemBo conditionItemBo : conditionItemBoList) {
                String displayText = ruleConditionItemBoConvertDisplayText(conditionItemBo);
                result.add(displayText);
            }
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        return result;
    }

    public List<String> convertResultStringToDisplayText(String resultDetail) {
        ObjectMapper objectMapper = new ObjectMapper();
        List<String> result = new ArrayList<>();
        try {
            List<RuleResultItemBo> resultItemBoList = objectMapper.readValue(resultDetail, new TypeReference<List<RuleResultItemBo>>() {
            });
            for (RuleResultItemBo resultItemBo : resultItemBoList) {
                String displayText = ruleResultItemBoConvertDisplayText(resultItemBo);
                result.add(displayText);
            }
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        return result;
    }

    public String ruleResultItemBoConvertDisplayText(RuleResultItemBo resultItemBo) {
        String field = resultItemBo.getFieldName();
        String resultTargetValue = getResultItemDisplayTargetValue(resultItemBo);
        return String.format(RESULT_DISPLAY_TEXT_FORMAT, field, resultTargetValue);
    }

    private String getResultItemDisplayTargetValue(RuleResultItemBo resultItemBo) {
        String fieldValueType = resultItemBo.getFieldValueType();
        String targetValue = "";
        switch (fieldValueType) {
            case "basic":
                // 基础类型
                targetValue = getResultItemBasicTypeDisplayTargetValue(resultItemBo);
                break;
            case "enumConstant":
                // 枚举类型
                targetValue = getResultItemEnumConstantDisplayTargetValue(resultItemBo);
                break;
        }
        return targetValue;
    }

    private String getResultItemEnumConstantDisplayTargetValue(RuleResultItemBo resultItemBo) {
        /**
         * 获取枚举常量下所有枚举明细项
         */
        List<ConstantItem> constantItemList = constantItemService.getConstantItemByEnumConstantKey(resultItemBo.getType());
        // 枚举常量转为map
        Map<String, ConstantItem> constantItemMap = new HashMap<>();
        for (ConstantItem constantItem : constantItemList) {
            constantItemMap.put(constantItem.getItemKey(), constantItem);
        }
        ValueType valueType = resultItemBo.getTargetValue().getValueType();
        FieldTypeStrategy fieldTypeStrategy = FieldTypeStrategyContext.getFieldTypeStrategy(resultItemBo.getFieldBasicType());
        String displayText = "";
        switch (valueType) {
            case SINGLE:
                Object single = resultItemBo.getTargetValue().getSingle();
                displayText = fieldTypeStrategy.getSingleValueDisplayText(constantItemMap.get(single.toString()).getItemName());
                break;
            case RANGE:
                Range range = resultItemBo.getTargetValue().getRange();
                String beginItem = constantItemMap.get(range.getBegin().toString()).getItemName();
                String endItem = constantItemMap.get(range.getEnd().toString()).getItemName();
                displayText = fieldTypeStrategy.getRangeValueDisplayText(new Range<>(beginItem, endItem));
                break;
            case COLLECTION:
                List list = resultItemBo.getTargetValue().getList();
                List<String> itemList = new ArrayList<>();
                for (Object item : list) {
                    itemList.add(constantItemMap.get(item.toString()).getItemName());
                }
                displayText = fieldTypeStrategy.getCollectionValueDisplayText(itemList);
                break;
        }
        return displayText;
    }

    private String getResultItemBasicTypeDisplayTargetValue(RuleResultItemBo resultItemBo) {
        ValueType valueType = resultItemBo.getTargetValue().getValueType();
        FieldTypeStrategy fieldTypeStrategy = FieldTypeStrategyContext.getFieldTypeStrategy(resultItemBo.getFieldBasicType());
        String displayText = "";
        switch (valueType) {
            case SINGLE:
                displayText = fieldTypeStrategy.getSingleValueDisplayText(resultItemBo.getTargetValue().getSingle());
                break;
            case RANGE:
                displayText = fieldTypeStrategy.getRangeValueDisplayText(resultItemBo.getTargetValue().getRange());
                break;
            case COLLECTION:
                displayText = fieldTypeStrategy.getCollectionValueDisplayText(resultItemBo.getTargetValue().getList());
                break;
        }
        return displayText;
    }
}
